﻿using System;
using System.Collections.Generic;
using System.Threading;

using Heaven.Graphics;
using Heaven.Engine.Concurrency;
using Heaven.Engine;

namespace Heaven.Engine
{
    /// <summary>
    /// Represents a collection of renderers
    /// </summary>
    public class RendererCollection : IEnumerable<Renderer>
    {
        #region Events

        // Weak event
        WeakMulticastDelegate invalidated = new WeakMulticastDelegate();

        /// <summary>
        /// Occurs when the collection has been changed
        /// </summary>
        internal event EventHandler Invalidated
        {
            add { invalidated.Add(value); }
            remove { invalidated.Remove(value); }
        }
        
        /// <summary>
        /// Indicate that the collection has been changed
        /// </summary>
        internal void Invalidate() { invalidated.Invoke(this, EventArgs.Empty); }
  
        #endregion

        #region Fields
                
        // Internal collection of nodes
        List<Renderer> items = new List<Renderer>();
        List<Renderer> shadow = new List<Renderer>();
        DeferredActions actions = new DeferredActions();

        #endregion

        #region Properties
               

        #endregion

        #region Methods

        /// <summary>
        /// Adds an item
        /// </summary>
        /// <param name="item">An item</param>
        public void Add(Renderer item)
        {
            items.Add(item);
            actions.Add(AddDeferred, item);
            
            item.Invalidated += new EventHandler(OnNodeInvalidated);
            Invalidate();
        }       

        /// <summary>
        /// Removes the given item
        /// </summary>
        /// <param name="item">An item</param>
        public void Remove(Renderer item)
        {
            items.Remove(item);
            actions.Add(RemoveDeferred, item);
           
            item.Invalidated -= new EventHandler(OnNodeInvalidated);
            Invalidate();
        }

        void AddDeferred(object[] input)
        {
            shadow.Add((Renderer)input[0]);
        }

        void RemoveDeferred(object[] input)
        {
            shadow.Remove((Renderer)input[0]);
        }

        #endregion

        #region Event's Handlers
        
        void OnNodeInvalidated(object sender, EventArgs e)
        {
            Invalidate();
        }

        #endregion

        #region Internals
                
        /// <summary>
        /// Synchronizes back-end data and front-end data
        /// </summary>
        void Synchronize()
        {
            actions.Perform();
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Default constructor
        /// </summary>
        public RendererCollection()
        {
        }        

        #endregion

        #region Enumerations

        /// <summary>
        /// Enumerates items
        /// </summary>
        /// <returns>A System.Collections.Generic.IEnumerable<Renderer> that 
        /// can be used to iterate through the collection</returns>
        internal IEnumerable<Renderer> Enumerate()
        {
            Synchronize();
            return shadow;
        }         

        /// <summary>
        /// Gets enumerator
        /// </summary>
        /// <returns>Enumerator</returns>
        public IEnumerator<Renderer> GetEnumerator()
        {
            return items.GetEnumerator();
        }


        /// <summary>
        /// Gets enumerator
        /// </summary>
        /// <returns>Enumerator</returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return items.GetEnumerator();
        }

        #endregion
    }
}
